package repo

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path"
	"strings"
)

type TraitDefinition struct {
	Name        string `json:"name"`
	DefVal      string `json:"defval"`
	Description string `json:"desc"`
}

type ModulePackage struct {
	PackageTags  string `json:"tags"`
	PackageName  string `json:"name"`
	PackageInner string `json:"inner"`
	HASH         string `json:"hash"`
	DownloadURL  string `json:"download"`
}

type ModuleVersionDescription struct {
	ModuleLabel     *ModuleLabel     `json:"label"`    // 模块的标签信息
	ModulePackages  []*ModulePackage `json:"packages"` // 模块的软件包
	RequiredModules []string         `json:"requires"` // 必选依赖模块
	Description     string           `json:"desc"`     // 文本描述
	// License            string            // License
	// TrainVersion       string // 选型火车版本
	//TrainModuleName    string // 在版本选型表中的名称
	//TrainModuleVersion string // 在版本选型表中的版本
	//ImportAs string // 模块导入方式
	TraitDefinitions map[string]*TraitDefinition `json:"traitdefs"`
}

// 来源/用途
func ReadModuleVersionDescription(label string) (*ModuleVersionDescription, error) {

	// 获得Label
	moduleLabel, err := ParseModuleLabel(label)
	if err != nil {
		return nil, fmt.Errorf("%v", err.Error())
	}

	// 确定版本文件
	moduleVersionFile := path.Join(PKGREPO, moduleLabel.ModuleName, moduleLabel.ModuleVersion, VERSIONED_STATUS_FILE)
	if !PathIsFile(moduleVersionFile) {
		return nil, fmt.Errorf("can not found module version file: '%v'", moduleVersionFile)
	}

	// 打开版本文件
	file, err := os.Open(moduleVersionFile)
	if err != nil {
		return nil, err
	}

	defer file.Close()

	// 创建一个行读取器
	reader := bufio.NewReader(file)

	// 预先准备好 ModuleVersionDescription
	moduleVersionDescription := &ModuleVersionDescription{}
	moduleVersionDescription.ModuleLabel = moduleLabel
	moduleVersionDescription.ModulePackages = make([]*ModulePackage, 0, 2)

	lineno := 0
	for {
		// 读取一行
		text, _, err := reader.ReadLine()
		if err == io.EOF {
			break
		}

		lineno++

		// 去掉行首尾空白
		line := string(bytes.TrimSpace(text))
		if (len(line) == 0) || (strings.HasPrefix(line, "#")) {
			continue
		}

		// 按空格拆分
		key, value := Cut(line)

		if key == "PACKAGE" {
			// 按空格拆分
			items := strings.Fields(value)
			if len(items) < 5 {
				return nil, fmt.Errorf("%v(%v): 'PACKAGE' need 6 sections", moduleVersionFile, lineno)
			}

			// 记录信息
			modulePackage := &ModulePackage{}
			modulePackage.PackageTags = items[0]
			modulePackage.PackageName = items[1]
			modulePackage.PackageInner = items[2]
			modulePackage.HASH = items[3]
			modulePackage.DownloadURL = items[4]
			moduleVersionDescription.ModulePackages = append(moduleVersionDescription.ModulePackages, modulePackage)
			continue
		}

		if key == "REQUIRED" {
			if value != "" {
				moduleVersionDescription.RequiredModules = append(moduleVersionDescription.RequiredModules, value)
			}
			continue
		}

		// if key == "LICENSE" {
		// 	moduleVersionDescription.License = value
		// 	continue
		// }

		if key == "DESCRIPTION" {
			moduleVersionDescription.Description = value
			continue
		}

		if key == "TRAITDEF" {
			//items := strings.Fields(value)

		}

		// if key == "TRAINVERSION" {
		// 	moduleVersionDescription.TrainVersion = value
		// 	continue
		// }

		// if key == "TRAINMODULENAME" {
		// 	moduleVersionDescription.TrainModuleName = value
		// 	continue
		// }

		// if key == "TRAINMODULEVERSION" {
		// 	moduleVersionDescription.TrainModuleVersion = value
		// 	continue
		// }

		//if key == "IMPORTAS" {
		//	moduleVersionDescription.ImportAs = value
		//	continue
		//}
	}

	// DESCRIPTION 是必须的
	if moduleVersionDescription.Description == "" {
		return nil, fmt.Errorf("%v(%v): missing 'DESCRIPTION'", moduleVersionFile, lineno)
	}

	// PACKAGE 是必须的
	if len(moduleVersionDescription.ModulePackages) == 0 {
		return nil, fmt.Errorf("%v(%v): missing 'PACKAGE'", moduleVersionFile, lineno)
	}

	// // LICENSE 是必须的
	// if moduleVersionDescription.License == "" {
	// 	return nil, fmt.Errorf("%v(%v): missing 'LICENSE'", moduleVersionFile, lineno)
	// }

	// IMPORTAS 是必须的
	//if moduleVersionDescription.ImportAs == "" {
	//	return nil, fmt.Errorf("%v(%v): missing 'IMPORTAS'", moduleVersionFile, lineno)
	//}

	// // 自动对 TRAINMODULENAME 做矫正
	// if moduleVersionDescription.TrainModuleName == "" {
	// 	moduleVersionDescription.TrainModuleName = moduleVersionDescription.ModuleLabel.ModuleName
	// }

	// // 自动对 TRAINMODULEVERSION 做矫正
	// if moduleVersionDescription.TrainModuleVersion == "" {
	// 	moduleVersionDescription.TrainModuleVersion = moduleVersionDescription.ModuleLabel.ModuleVersion
	// }

	return moduleVersionDescription, nil
}

func WriteModuleVersionDescription(descriptor *ModuleVersionDescription) error {
	modverFile := path.Join(PKGREPO, descriptor.ModuleLabel.ModuleName, descriptor.ModuleLabel.ModuleVersion, VERSIONED_STATUS_FILE)
	modverFileBak := path.Join(PKGREPO, descriptor.ModuleLabel.ModuleName, descriptor.ModuleLabel.ModuleVersion, "."+VERSIONED_STATUS_FILE+".backup")
	modverFileNew := path.Join(PKGREPO, descriptor.ModuleLabel.ModuleName, descriptor.ModuleLabel.ModuleVersion, "."+VERSIONED_STATUS_FILE+".new")

	if true {
		file, err := os.OpenFile(modverFileNew, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0750)
		if err != nil {
			return err
		}

		// DESCRIPTION
		fmt.Fprintf(file, "%-19v %v\n", "DESCRIPTION", descriptor.Description)

		// PACKAGE
		if len(descriptor.ModulePackages) == 0 {
			fmt.Fprintf(file, "%-19v %v %v %v %v %v\n", "PACKAGE", "-", "-", "-", "-", "-")
		} else {
			for _, pkg := range descriptor.ModulePackages {
				packageTags := pkg.PackageTags
				if packageTags == "" {
					packageTags = "-"
				}

				packageName := pkg.PackageName
				if packageName == "" {
					packageName = "-"
				}

				packageInner := pkg.PackageInner
				if packageInner == "" {
					packageInner = "-"
				}

				url := pkg.DownloadURL
				if url == "" {
					url = "-"
				}

				HASH := pkg.HASH
				if HASH == "" {
					HASH = "-"
				}

				fmt.Fprintf(file, "%-19v %v %v %v %v %v\n", "PACKAGE", packageTags, packageName, packageInner, url, HASH)
			}
		}

		// REQUIRED
		if len(descriptor.RequiredModules) == 0 {
			fmt.Fprintf(file, "%-19v %v\n", "REQUIRED", "")
		} else {
			for _, req := range descriptor.RequiredModules {
				fmt.Fprintf(file, "%-19v %v\n", "REQUIRED", req)
			}
		}

		// // LICENSE
		// fmt.Fprintf(file, "%-19v %v\n", "LICENSE", descriptor.License)

		// IMPORTAS
		//fmt.Fprintf(file, "%-19v %v\n", "IMPORTAS", descriptor.ImportAs)

		// // TRAINVERSION
		// fmt.Fprintf(file, "%-19v %v\n", "TRAINVERSION", descriptor.TrainVersion)

		// // TRAINMODULENAME
		// trainModuleName := ""
		// if descriptor.TrainModuleName != descriptor.ModuleLabel.ModuleName {
		// 	trainModuleName = descriptor.TrainModuleName
		// }
		// fmt.Fprintf(file, "%-19v %v\n", "TRAINMODULENAME", trainModuleName)

		// // TRAINMODULEVERSION
		// trainModuleVersion := ""
		// if descriptor.TrainModuleVersion != descriptor.ModuleLabel.ModuleVersion {
		// 	trainModuleVersion = descriptor.TrainModuleVersion
		// }
		// fmt.Fprintf(file, "%-19v %v\n", "TRAINMODULEVERSION", trainModuleVersion)

		// 关闭文件
		file.Close()
	}

	if PathIsFile(modverFileBak) {
		os.Remove(modverFileBak)
		if PathIsFile(modverFileBak) {
			return fmt.Errorf("can not remove backuo file: %v", modverFileBak)
		}
	}

	os.Rename(modverFile, modverFileBak)
	err := os.Rename(modverFileNew, modverFile)
	if err != nil {
		return fmt.Errorf("can not rename file: %v", err.Error())
	}

	return nil
}

func DumpToJson(d *ModuleVersionDescription) (string, error) {
	r, err := json.Marshal(d)
	if err != nil {
		fmt.Errorf("dump `%v' failed: %v", "export", err.Error())
		return "", err
	}

	return string(r), nil
}

func LoadFromJson(s string) (*ModuleVersionDescription, error) {
	versionDesc := &ModuleVersionDescription{}
	err := json.Unmarshal([]byte(s), versionDesc)
	if err != nil {
		fmt.Errorf("dump `%v' failed: %v", "export", err.Error())
		return nil, err
	}

	return versionDesc, nil
}
